/*
 * ***** BEGIN GPL LICENSE BLOCK *****
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
 * All rights reserved.
 *
 * The Original Code is: all of this file.
 *
 * Contributor(s): none yet.
 *
 * ***** END GPL LICENSE BLOCK *****
 */

/** \file ghost/intern/GHOST_WindowX11.cpp
 *  \ingroup GHOST
 */

/* For standard X11 cursors */
#include <X11/cursorfont.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#ifdef WITH_X11_ALPHA
#include <X11/extensions/Xrender.h>
#endif
#include "GHOST_WindowX11.h"
#include "GHOST_SystemX11.h"
#include "STR_String.h"
#include "GHOST_Debug.h"

#ifdef WITH_XDND
#  include "GHOST_DropTargetX11.h"
#endif

#if defined(WITH_GL_EGL)
#  include "GHOST_ContextEGL.h"
#else
#  include "GHOST_ContextGLX.h"
#endif

/* for XIWarpPointer */
#ifdef WITH_X11_XINPUT
#  include <X11/extensions/XInput2.h>
#endif

//For DPI value
#include <X11/Xresource.h>

#include <cstring>
#include <cstdio>

/* gethostname */
#include <unistd.h>

#include <algorithm>
#include <string>
#include <math.h>

/* For obscure full screen mode stuff
 * lifted verbatim from blut. */

typedef struct {
	long flags;
	long functions;
	long decorations;
	long input_mode;
} MotifWmHints;

#define MWM_HINTS_DECORATIONS         (1L << 1)

#ifndef HOST_NAME_MAX
#  define HOST_NAME_MAX 64
#endif

// #define GHOST_X11_GRAB

/*
 * A Client can't change the window property, that is
 * the work of the window manager. In case, we send
 * a ClientMessage to the RootWindow with the property
 * and the Action (WM-spec define this):
 */
#define _NET_WM_STATE_REMOVE 0
#define _NET_WM_STATE_ADD 1
// #define _NET_WM_STATE_TOGGLE 2 // UNUSED

/*
 * import bpy
 * ima = bpy.data.images["blender.png"]
 * w, h = ima.size
 * print("%d,%d," % (w, h))
 * for y in range(h - 1, -1, -1):
 *     px = []
 *     for x in range(w):
 *         p = ((y * w) + x) * 4
 *         rgba = ima.pixels[p : p + 4]
 *         rgba = rgba[2], rgba[1], rgba[0], rgba[3]
 *         px.append(sum((int(p * 255) << (8 * i)) for i, p in enumerate(rgba)))
 *     print(", ".join([str(p) for p in px]), end=",\n")
 */

/**
 * See the python script above to regenerate the 48x48 icon within blender
 *
 * \note Using 'unsigned' to avoid `-Wnarrowing` warning.
 */
static const unsigned long BLENDER_ICON_48x48x32[] = {
	48,48,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 131820800, 1305304320, 2547014912, 1808620800, 432823296, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 3218103552, 4074070530, 4276450320, 4124995601, 4090518785, 1624202496, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 1053710848, 4140916224, 4294348072, 4294483011, 4294483268, 4294153273, 4107626765, 2765053184, 146759680, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 282025984, 4124007680, 4293884685, 4294482752, 4294483785, 4294483785, 4294417734, 4141905692, 3671088640, 600596224, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 1573804544, 4124073472, 4293555207, 4294416700, 4294484558, 4294484558, 4294484558, 4260005935, 4073807875, 1355766784, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 936140032, 3973012736, 4192300034, 4294415154, 4294485331, 4294485074, 4294485074, 4294088514, 4107560459, 2463128832, 79642624, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 399726848, 3452984576, 4107887616, 4294281765, 4294485590, 4294485591, 4294485590, 4294418767, 4124931612, 3469762048, 449730560, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 97281536, 2597412096, 4107427584, 4293951767, 4294485590, 4294551642, 4294486105, 4294485847, 4226320176, 4023344642, 1120754944, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 1389190400, 2949668096, 4073741568, 4291714048, 4291714048, 4291714048, 4291714048, 4291714048, 4291714048, 4291714048, 4291714048, 4291714048, 4291714048, 4291714048, 4291714048, 4291714048, 4291714048, 4291714048, 4291714048, 4291714048, 4158482693, 4294484301, 4294552415, 4294552157, 4294551899, 4294486105, 4293957442, 4124206089, 2144427008, 33488896, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 1171217408, 4107361792, 4293425685, 4294218035, 4294482753, 4294483268, 4294483783, 4294484043, 4294484558, 4294484817, 4294485331, 4294485591, 4294486105, 4294551899, 4294552157, 4294552415, 4294552672, 4294552673, 4294552930, 4294552674, 4294552674, 4294553188, 4294553190, 4294552932, 4294552674, 4294552415, 4294552156, 4294551642, 4294287696, 4124733464, 3234946560, 315970816, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 3838860800, 4293620999, 4294416700, 4294482753, 4294483269, 4294483784, 4294484300, 4294484816, 4294485331, 4294485591, 4294551642, 4294552157, 4294552672, 4294552931, 4294553446, 4294553704, 4294553962, 4294554220, 4294554221, 4294554221, 4294554220, 4294554220, 4294553962, 4294553704, 4294553190, 4294552931, 4294552416, 4294552157, 4294551642, 4294485590, 4192502315, 3939458305, 919624192, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 3838860800, 4293751810, 4294415669, 4294482753, 4294483268, 4294483784, 4294484300, 4294484816, 4294485331, 4294485591, 4294551642, 4294552157, 4294552932, 4294553447, 4294553962, 4294554220, 4294554479, 4294554737, 4294554994, 4294554994, 4294554994, 4294554737, 4294554479, 4294554220, 4294553705, 4294553446, 4294552931, 4294552416, 4294552156, 4294486105, 4294485589, 4293824827, 4124140038, 1741708800, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 2463128832, 4191905024, 4294145792, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294345234, 4294553447, 4294554221, 4294554736, 4294620787, 4294621045, 4294621047, 4294621303, 4294621047, 4294621045, 4294554995, 4294554737, 4294554220, 4294553705, 4294553190, 4294552930, 4294552414, 4294551899, 4294485847, 4294485590, 4294155594, 4141050128, 1573936384, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 248011520, 2983288320, 4191116288, 4174405120, 4174405120, 4174405120, 4174405120, 4174405120, 4174405120, 4174405120, 4174405120, 4207959552, 4294214422, 4294554220, 4294554736, 4294620787, 4294621046, 4294621562, 4294621820, 4294690967, 4294761660, 4294830292, 4294899180, 4294966780, 4294898406, 4294829002, 4294759597, 4294621304, 4294552416, 4294551900, 4294485848, 4294485332, 4294485590, 4294221646, 4140984079, 1204641024, 4671303, 4671303, 4671303, 4671303, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 79642624, 282025984, 282025984, 282025984, 282025984, 282025984, 282025984, 1540316160, 4124007680, 4226185237, 4294552156, 4294554221, 4294554737, 4294620789, 4294621561, 4294623367, 4294829774, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294966778, 4294759856, 4294552674, 4294486105, 4294485589, 4294484817, 4294551127, 4294089804, 4090651658, 885939456, 4671303, 4671303, 4671303, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 97281536, 2513394688, 4124139264, 4293888040, 4294552931, 4294553705, 4294554478, 4294554737, 4294621045, 4294692513, 4294900470, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294898922, 4294621046, 4294485589, 4294484817, 4294484558, 4294551383, 4293891393, 4023344385, 432823296, 4671303, 4671303, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 583752192, 3604045056, 4124796420, 4294285115, 4294552672, 4294553189, 4294553704, 4294554220, 4294554736, 4294623367, 4294769142, 4294835709, 4294835709, 4294835709, 4293192946, 4289446870, 4287803851, 4286620866, 4287738058, 4289446871, 4293850103, 4294901502, 4294901502, 4294901502, 4294898406, 4294552157, 4294484816, 4294484301, 4294484299, 4294486105, 4192502057, 2530172416, 4671303, 4671303, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 1473075968, 4090518784, 4259673101, 4294484042, 4294551899, 4294552415, 4294552931, 4294553447, 4294553962, 4294554995, 4294700770, 4294704123, 4294704123, 4294769916, 4290169563, 4286555330, 4286423745, 4286292416, 4286095038, 4285897917, 4285635259, 4285766844, 4291155427, 4294769916, 4294769916, 4294769916, 4294628011, 4294278923, 4294278408, 4294278149, 4294279181, 4294149404, 4140784896, 365846784, 4671303, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 163992832, 2731564288, 4124205057, 4293952286, 4294484816, 4294485590, 4294551642, 4294552157, 4294552673, 4294553188, 4294553704, 4294561702, 4294572537, 4294572537, 4294638330, 4291023841, 4286226623, 4286226623, 4286160831, 4286029502, 4285832381, 4285700795, 4284977846, 4282414755, 4280706199, 4290629597, 4294572537, 4294572537, 4294572537, 4294350393, 4294277376, 4294277376, 4294277633, 4294413864, 4158482692, 1875663872, 4671303, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 718166784, 3738197248, 4141705477, 4294283568, 4294484815, 4294484816, 4294485332, 4294485848, 4294551899, 4294552158, 4294552673, 4294553188, 4294500036, 4294440951, 4294506744, 4294243830, 4286292159, 4285963709, 4285898173, 4285832381, 4285766588, 4285372345, 4282349219, 4279391885, 4279063179, 4279063179, 4281954719, 4294375158, 4294375158, 4294375158, 4294357617, 4294277376, 4294277376, 4294277376, 4294346781, 4293557270, 3218103552, 4671303, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 1691311104, 4124007936, 4276647182, 4294416701, 4294483784, 4294484043, 4294484558, 4294485073, 4294485332, 4294485848, 4294551899, 4294552158, 4294552672, 4294372579, 4294375158, 4294375158, 4291943654, 4285569467, 4285635003, 4285569467, 4285503674, 4282875047, 4279654800, 4279063179, 4279063179, 4279063179, 4279063179, 4279128971, 4292732137, 4294177779, 4294177779, 4294233511, 4294277376, 4294277376, 4294277376, 4294344717, 4294217516, 4140784640, 50298880, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 232284672, 2949668096, 4107559426, 4294017820, 4294416960, 4294482753, 4294483268, 4294416959, 4294413348, 4294347296, 4294417474, 4294485332, 4294485848, 4294551642, 4294487137, 4294177779, 4294243572, 4294243572, 4290958047, 4285306552, 4285306553, 4284583603, 4280509077, 4279063179, 4279063179, 4279063179, 4279063179, 4279063179, 4279063179, 4279063179, 4291417567, 4293980400, 4294046193, 4294107085, 4294277376, 4294277376, 4294277376, 4294277376, 4294416185, 4207959811, 232284672, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 852253696, 3855638016, 4158614278, 4294348586, 4294416701, 4294416443, 4294416958, 4294415411, 4294280731, 4108283403, 4243290129, 4294414638, 4294484817, 4294485331, 4294485590, 4294485848, 4294174941, 4294111986, 4294111986, 4292206309, 4284977846, 4283137961, 4279457678, 4279063179, 4279063179, 4279063179, 4279063179, 4279063179, 4279063179, 4279063179, 4279457422, 4293454571, 4293848814, 4293848814, 4294035617, 4294277376, 4294277376, 4294277376, 4294277376, 4294416443, 4140916998, 365846784, 4671303,
	4671303, 4671303, 4671303, 4671303, 1909480704, 4124073472, 4293490704, 4294415154, 4294415669, 4294415669, 4294416184, 4294414123, 4294083611, 4090914310, 4040055808, 4293161999, 4294414379, 4294484557, 4294484815, 4294485074, 4294485331, 4294104247, 4293914607, 4293914607, 4293783279, 4283334569, 4279063179, 4279063179, 4279063179, 4279063179, 4279063179, 4279063179, 4279063179, 4279063179, 4279063179, 4284057260, 4293585642, 4293651435, 4293651435, 4293962857, 4294277376, 4294277376, 4294277376, 4294277376, 4294416959, 4124205832, 499800064, 4671303,
	4671303, 4671303, 298998272, 3150929152, 4107690755, 4294018076, 4294415410, 4294414636, 4294414638, 4294415153, 4294413606, 4293886234, 4124205059, 2110675968, 2060409856, 4225921807, 4294414895, 4294483785, 4294484043, 4294484557, 4294484815, 4294164622, 4293783021, 4293717228, 4293388263, 4290299602, 4279326093, 4279063179, 4279063179, 4279063179, 4279063179, 4279063179, 4279063179, 4279063179, 4280245907, 4292205535, 4293454056, 4293454056, 4293454056, 4294086704, 4294277376, 4294277376, 4294277376, 4294277891, 4294417992, 4207894017, 97281536, 4671303,
	4671303, 50298880, 3503250688, 4192169224, 4294282278, 4294414381, 4294347813, 4294413865, 4294414122, 4294348070, 4259937303, 4090519041, 1305304320, 4671303, 1238260480, 4024002053, 4294415926, 4294483269, 4294483527, 4294483784, 4294484043, 4294419022, 4293712069, 4293190884, 4293059298, 4293059298, 4289905102, 4281297305, 4279063179, 4279063179, 4279063179, 4279063179, 4279063179, 4282677154, 4291351001, 4293256677, 4293256677, 4293256677, 4293639310, 4294277376, 4294277376, 4294277376, 4294277376, 4294345490, 4294022463, 3671088640, 4671303, 4671303,
	4671303, 2077187328, 4107822598, 4294348586, 4294347555, 4294347039, 4294347554, 4294348069, 4294348327, 4175590163, 3872349440, 718166784, 4671303, 4671303, 449730560, 4124073472, 4294414379, 4294417217, 4294483010, 4294483268, 4294483269, 4294415927, 4294084898, 4292925905, 4292861919, 4292861919, 4292927712, 4292533470, 4288656582, 4286094006, 4284517036, 4286685370, 4289379531, 4292927713, 4293059298, 4293059298, 4293059298, 4293251260, 4294212873, 4294277376, 4294277376, 4294277376, 4294277376, 4294414896, 4259939884, 2681167104, 4671303, 4671303,
	97281536, 4191116288, 4294084386, 4294413347, 4294346265, 4294346780, 4294413091, 4294282281, 4124732172, 3335609856, 315970816, 4671303, 4671303, 4671303, 16777216, 3452853504, 4293624609, 4294415670, 4294416702, 4294416959, 4294414121, 4294277634, 4294277376, 4293825597, 4292793547, 4292664540, 4292730333, 4292730333, 4292730333, 4292730333, 4292796126, 4292796126, 4292796126, 4292796126, 4292861919, 4292861919, 4293120190, 4294085156, 4294277376, 4294277376, 4294277376, 4294277376, 4294278149, 4294485332, 4074071305, 969825792, 4671303, 4671303,
	198270208, 4224605184, 4294282535, 4294413347, 4294346524, 4294348070, 4294085417, 4107559687, 2563792384, 79642624, 4671303, 4671303, 83886080, 184549376, 268435456, 1605258752, 4074137355, 4294416185, 4294346522, 4294278666, 4294277376, 4294277376, 4294277376, 4294277376, 4294213647, 4293243263, 4292532696, 4292532954, 4292532954, 4292598747, 4292598747, 4292598747, 4292598747, 4292664540, 4292794579, 4293568616, 4294212357, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294414895, 4293890877, 3570425344, 4671303, 4671303, 4671303,
	4671303, 3352387072, 4192301839, 4294282279, 4294019626, 4192302873, 4124139523, 1708088576, 4671303, 4671303, 67108864, 184549376, 285212672, 385875968, 486539264, 638387968, 3888864256, 4276847393, 4294414896, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4293954086, 4293502050, 4293179274, 4292855728, 4292662218, 4292920489, 4293243778, 4293501275, 4294083608, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294345491, 4294420571, 4107626251, 1322146816, 4671303, 4671303, 4671303,
	4671303, 382819584, 3134217472, 4191116288, 3939458560, 2211470592, 533617152, 4671303, 4671303, 117440512, 218103808, 335544320, 436207616, 553648128, 654311424, 771751936, 1534079488, 4157496833, 4294219326, 4294346523, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294278150, 4294485590, 4175527207, 2932497152, 117440512, 4671303, 4671303, 4671303,
	4671303, 4671303, 4671303, 50298880, 33488896, 4671303, 4671303, 4671303, 83886080, 201326592, 318767104, 436207616, 553648128, 671088640, 788529152, 889192448, 1006632960, 2493203712, 4157958415, 4294352457, 4294347039, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294278924, 4294486105, 4260073533, 3872218112, 525476096, 218103808, 100663296, 4671303, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 16777216, 134217728, 251658240, 369098752, 486539264, 603979776, 721420288, 855638016, 973078528, 1090519040, 1207959552, 2930002688, 4174604044, 4294221386, 4294414637, 4294277634, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294346522, 4294552931, 4226189107, 3888929792, 997536768, 385875968, 251658240, 150994944, 16777216, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 16777216, 134217728, 251658240, 369098752, 486539264, 603979776, 721420288, 855638016, 956301312, 1073741824, 1191182336, 1325400064, 2693873664, 4191117319, 4293891393, 4294485073, 4294347296, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294344717, 4294484299, 4294421863, 4208884260, 3687340544, 910958848, 503316480, 385875968, 251658240, 134217728, 16777216, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 83886080, 201326592, 318767104, 436207616, 536870912, 671088640, 771751936, 889192448, 989855744, 1107296256, 1207959552, 1325400064, 2187996928, 3972487680, 4191711513, 4294156111, 4294485591, 4294415926, 4294346007, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294278408, 4294414379, 4294484817, 4294554221, 4259941691, 4157628420, 2746568960, 807735296, 553648128, 436207616, 318767104, 218103808, 83886080, 4671303, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 100663296, 218103808, 318767104, 436207616, 536870912, 637534208, 754974720, 855638016, 956301312, 1040187392, 1140850688, 1224736768, 1342833408, 2677293568, 4174142464, 4157959447, 4276718648, 4294288986, 4294554220, 4294552415, 4294485074, 4294484300, 4294551641, 4294553705, 4294554738, 4294025043, 4175528237, 4174405895, 3384956928, 1264790528, 654311424, 553648128, 436207616, 335544320, 218103808, 117440512, 4671303, 4671303, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 50331648, 167772160, 268435456, 385875968, 469762048, 553648128, 654311424, 738197504, 822083584, 905969664, 973078528, 1023410176, 1090519040, 1208878848, 2054632960, 3165868032, 4123810816, 4224671493, 4157762069, 4124604196, 4141644844, 4124471839, 4174538769, 4241448451, 3586611712, 2275493888, 1078731776, 671088640, 570425344, 486539264, 385875968, 285212672, 184549376, 67108864, 4671303, 4671303, 4671303, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 67108864, 167772160, 251658240, 335544320, 419430400, 503316480, 570425344, 637534208, 704643072, 738197504, 788529152, 822083584, 855638016, 872415232, 889192448, 1042616320, 1365125376, 1702770688, 1821064448, 1467299072, 1095443200, 738985472, 637534208, 587202560, 503316480, 436207616, 352321536, 268435456, 184549376, 67108864, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 16777216, 67108864, 150994944, 234881024, 301989888, 352321536, 402653184, 452984832, 486539264, 520093696, 536870912, 553648128, 570425344, 570425344, 553648128, 536870912, 520093696, 486539264, 452984832, 402653184, 352321536, 301989888, 234881024, 167772160, 67108864, 16777216, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 50331648, 83886080, 134217728, 167772160, 201326592, 218103808, 234881024, 251658240, 251658240, 234881024, 218103808, 201326592, 167772160, 134217728, 83886080, 50331648, 16777216, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303,
	4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303,
};

static XVisualInfo *x11_visualinfo_from_glx(
        Display *display,
        bool stereoVisual,
        GHOST_TUns16 *r_numOfAASamples,
        bool needAlpha,
        GLXFBConfig *fbconfig)
{
	XVisualInfo *visual = NULL;
	GHOST_TUns16 numOfAASamples = *r_numOfAASamples;
	int glx_major, glx_minor, glx_version; /* GLX version: major.minor */
	GHOST_TUns16 actualSamples;
	int glx_attribs[64];

	*fbconfig = NULL;

	/* Set up the minimum attributes that we require and see if
	 * X can find us a visual matching those requirements. */

	if (!glXQueryVersion(display, &glx_major, &glx_minor)) {
		fprintf(stderr,
		        "%s:%d: X11 glXQueryVersion() failed, "
		        "verify working openGL system!\n",
		        __FILE__, __LINE__);

		return NULL;
	}
	glx_version = glx_major*100 + glx_minor;

	if (glx_version >= 104) {
		actualSamples = numOfAASamples;
	}
	else {
		numOfAASamples = 0;
		actualSamples = 0;
	}

#ifdef WITH_X11_ALPHA
	if (   needAlpha
	    && glx_version >= 103
	    && (glXChooseFBConfig ||
	        (glXChooseFBConfig = (PFNGLXCHOOSEFBCONFIGPROC)glXGetProcAddressARB((const GLubyte *)"glXChooseFBConfig")) != NULL)
	    && (glXGetVisualFromFBConfig ||
	        (glXGetVisualFromFBConfig = (PFNGLXGETVISUALFROMFBCONFIGPROC)glXGetProcAddressARB((const GLubyte *)"glXGetVisualFromFBConfig")) != NULL)
	    ) {
		GLXFBConfig *fbconfigs;
		int nbfbconfig;
		int i;

		for (;;) {

			GHOST_X11_GL_GetAttributes(glx_attribs, 64, actualSamples, stereoVisual, needAlpha, true);

			fbconfigs = glXChooseFBConfig(display, DefaultScreen(display), glx_attribs, &nbfbconfig);

			/* Any sample level or even zero, which means oversampling disabled, is good
			 * but we need a valid visual to continue */
			if (nbfbconfig > 0) {
				/* take a frame buffer config that has alpha cap */
				for (i=0 ;i<nbfbconfig; i++) {
					visual = (XVisualInfo*)glXGetVisualFromFBConfig(display, fbconfigs[i]);
					if (!visual)
						continue;
					/* if we don't need a alpha background, the first config will do, otherwise
					 * test the alphaMask as it won't necessarily be present */
					if (needAlpha) {
						XRenderPictFormat *pict_format = XRenderFindVisualFormat(display, visual->visual);
						if (!pict_format)
							continue;
						if (pict_format->direct.alphaMask <= 0)
							continue;
					}
					*fbconfig = fbconfigs[i];
					break;
				}
				XFree(fbconfigs);
				if (i<nbfbconfig) {
					if (actualSamples < numOfAASamples) {
						fprintf(stderr,
						        "Warning! Unable to find a multisample pixel format that supports exactly %d samples. "
						        "Substituting one that uses %d samples.\n",
						        numOfAASamples, actualSamples);
					}
					break;
				}
				visual = NULL;
			}

			if (actualSamples == 0) {
				/* All options exhausted, cannot continue */
				fprintf(stderr,
				        "%s:%d: X11 glXChooseVisual() failed, "
				        "verify working openGL system!\n",
				        __FILE__, __LINE__);

				return NULL;
			}
			else {
				--actualSamples;
			}
		}
	}
	else
#endif
	{
		/* legacy, don't use extension */
		for (;;) {
			GHOST_X11_GL_GetAttributes(glx_attribs, 64, actualSamples, stereoVisual, needAlpha, false);

			visual = glXChooseVisual(display, DefaultScreen(display), glx_attribs);

			/* Any sample level or even zero, which means oversampling disabled, is good
			 * but we need a valid visual to continue */
			if (visual != NULL) {
				if (actualSamples < numOfAASamples) {
					fprintf(stderr,
					        "Warning! Unable to find a multisample pixel format that supports exactly %d samples. "
					        "Substituting one that uses %d samples.\n",
					        numOfAASamples, actualSamples);
				}
				break;
			}

			if (actualSamples == 0) {
				/* All options exhausted, cannot continue */
				fprintf(stderr,
				        "%s:%d: X11 glXChooseVisual() failed, "
				        "verify working openGL system!\n",
				        __FILE__, __LINE__);

				return NULL;
			}
			else {
				--actualSamples;
			}
		}
	}
	*r_numOfAASamples = actualSamples;
	return visual;
}

GHOST_WindowX11::
GHOST_WindowX11(GHOST_SystemX11 *system,
        Display *display,
        const STR_String &title,
        GHOST_TInt32 left,
        GHOST_TInt32 top,
        GHOST_TUns32 width,
        GHOST_TUns32 height,
        GHOST_TWindowState state,
        const GHOST_TEmbedderWindowID parentWindow,
        GHOST_TDrawingContextType type,
        const bool stereoVisual,
        const bool exclusive,
        const bool alphaBackground,
        const GHOST_TUns16 numOfAASamples, const bool is_debug)
    : GHOST_Window(width, height, state, stereoVisual, exclusive, numOfAASamples),
      m_display(display),
      m_visualInfo(NULL),
      m_fbconfig(NULL),
      m_normal_state(GHOST_kWindowStateNormal),
      m_system(system),
      m_invalid_window(false),
      m_empty_cursor(None),
      m_custom_cursor(None),
      m_visible_cursor(None),
      m_taskbar("blender.desktop"),
#ifdef WITH_XDND
      m_dropTarget(NULL),
#endif
#if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
      m_xic(NULL),
#endif
      m_valid_setup(false),
      m_is_debug_context(is_debug)
{
	if (type == GHOST_kDrawingContextTypeOpenGL) {
		m_visualInfo = x11_visualinfo_from_glx(m_display, stereoVisual, &m_wantNumOfAASamples, alphaBackground, (GLXFBConfig*)&m_fbconfig);
	}
	else {
		XVisualInfo tmp = {0};
		int n;
		m_visualInfo = XGetVisualInfo(m_display, 0, &tmp, &n);
	}

	/* caller needs to check 'getValid()' */
	if (m_visualInfo == NULL) {
		fprintf(stderr, "initial window could not find the GLX extension\n");
		return;
	}

	unsigned int xattributes_valuemask = 0;

	XSetWindowAttributes xattributes;
	memset(&xattributes, 0, sizeof(xattributes));

	xattributes_valuemask |= CWBorderPixel;
	xattributes.border_pixel = 0;

	/* Specify which events we are interested in hearing. */

	xattributes_valuemask |= CWEventMask;
	xattributes.event_mask =
	        ExposureMask | StructureNotifyMask |
	        KeyPressMask | KeyReleaseMask |
	        EnterWindowMask | LeaveWindowMask |
	        ButtonPressMask | ButtonReleaseMask |
	        PointerMotionMask | FocusChangeMask |
	        PropertyChangeMask | KeymapStateMask;

	if (exclusive) {
		xattributes_valuemask |= CWOverrideRedirect;
		xattributes.override_redirect = True;
	}

	xattributes_valuemask |= CWColormap;
	xattributes.colormap = XCreateColormap(
	        m_display,
	        RootWindow(m_display, m_visualInfo->screen),
	        m_visualInfo->visual,
	        AllocNone
	        );

	/* create the window! */
	if (parentWindow == 0) {
		m_window =  XCreateWindow(
		        m_display,
		        RootWindow(m_display, m_visualInfo->screen),
		        left, top, width, height,
		        0, /* no border. */
		        m_visualInfo->depth,
		        InputOutput,
		        m_visualInfo->visual,
		        xattributes_valuemask,
		        &xattributes);
	}
	else {
		Window root_return;
		int x_return, y_return;
		unsigned int w_return, h_return, border_w_return, depth_return;

		XGetGeometry(m_display, parentWindow, &root_return, &x_return, &y_return,
		             &w_return, &h_return, &border_w_return, &depth_return);

		left = 0;
		top = 0;
		width = w_return;
		height = h_return;


		m_window = XCreateWindow(
		        m_display,
		        parentWindow, /* reparent against embedder */
		        left, top, width, height,
		        0, /* no border. */
		        m_visualInfo->depth,
		        InputOutput,
		        m_visualInfo->visual,
		        xattributes_valuemask,
		        &xattributes);

		XSelectInput(m_display, parentWindow, SubstructureNotifyMask);

	}

#ifdef WITH_XDND
	/* initialize drop target for newly created window */
	m_dropTarget = new GHOST_DropTargetX11(this, m_system);
	GHOST_PRINT("Set drop target\n");
#endif

	if (state == GHOST_kWindowStateMaximized || state == GHOST_kWindowStateFullScreen) {
		Atom atoms[2];
		int count = 0;
		if (state == GHOST_kWindowStateMaximized) {
			atoms[count++] = m_system->m_atom._NET_WM_STATE_MAXIMIZED_VERT;
			atoms[count++] = m_system->m_atom._NET_WM_STATE_MAXIMIZED_HORZ;
		}
		else {
			atoms[count++] = m_system->m_atom._NET_WM_STATE_FULLSCREEN;
		}

		XChangeProperty(m_display, m_window, m_system->m_atom._NET_WM_STATE, XA_ATOM, 32,
		                PropModeReplace, (unsigned char *)atoms, count);
		m_post_init = False;
	}
	/*
	 * One of the problem with WM-spec is that can't set a property
	 * to a window that isn't mapped. That is why we can't "just
	 * call setState" here.
	 *
	 * To fix this, we first need know that the window is really
	 * map waiting for the MapNotify event.
	 *
	 * So, m_post_init indicate that we need wait for the MapNotify
	 * event and then set the Window state to the m_post_state.
	 */
	else if ((state != GHOST_kWindowStateNormal) && (state != GHOST_kWindowStateMinimized)) {
		m_post_init = True;
		m_post_state = state;
	}
	else {
		m_post_init = False;
		m_post_state = GHOST_kWindowStateNormal;
	}


	/* Create some hints for the window manager on how
	 * we want this window treated. */
	{
		XSizeHints *xsizehints = XAllocSizeHints();
		xsizehints->flags = PPosition | PSize | PMinSize | PMaxSize;
		xsizehints->x = left;
		xsizehints->y = top;
		xsizehints->width = width;
		xsizehints->height = height;
		xsizehints->min_width = 320;     /* size hints, could be made apart of the ghost api */
		xsizehints->min_height = 240;    /* limits are also arbitrary, but should not allow 1x1 window */
		xsizehints->max_width = 65535;
		xsizehints->max_height = 65535;
		XSetWMNormalHints(m_display, m_window, xsizehints);
		XFree(xsizehints);
	}


	/* XClassHint, title */
	{
		XClassHint *xclasshint = XAllocClassHint();
		const int len = title.Length() + 1;
		char *wmclass = (char *)malloc(sizeof(char) * len);
		memcpy(wmclass, title.ReadPtr(), len * sizeof(char));
		xclasshint->res_name = wmclass;
		xclasshint->res_class = wmclass;
		XSetClassHint(m_display, m_window, xclasshint);
		free(wmclass);
		XFree(xclasshint);
	}


	/* The basic for a good ICCCM "work" */
	if (m_system->m_atom.WM_PROTOCOLS) {
		Atom atoms[2];
		int natom = 0;

		if (m_system->m_atom.WM_DELETE_WINDOW) {
			atoms[natom] = m_system->m_atom.WM_DELETE_WINDOW;
			natom++;
		}

		if (m_system->m_atom.WM_TAKE_FOCUS && m_system->m_windowFocus) {
			atoms[natom] = m_system->m_atom.WM_TAKE_FOCUS;
			natom++;
		}

		if (natom) {
			/* printf("Register atoms: %d\n", natom); */
			XSetWMProtocols(m_display, m_window, atoms, natom);
		}
	}

	/* Set the window hints */
	{
		XWMHints *xwmhints = XAllocWMHints();
		xwmhints->initial_state = NormalState;
		xwmhints->input = (m_system->m_windowFocus) ? True : False;
		xwmhints->flags = InputHint | StateHint;
		XSetWMHints(display, m_window, xwmhints);
		XFree(xwmhints);
	}


	/* set the icon */
	{
		Atom _NET_WM_ICON     = XInternAtom(m_display, "_NET_WM_ICON", False);
		XChangeProperty(m_display, m_window, _NET_WM_ICON, XA_CARDINAL,
		                32, PropModeReplace, (unsigned char *)BLENDER_ICON_48x48x32,
		                BLENDER_ICON_48x48x32[0] * BLENDER_ICON_48x48x32[1] + 2);
	}

	/* set the process ID (_NET_WM_PID) */
	{
		Atom _NET_WM_PID = XInternAtom(m_display, "_NET_WM_PID", False);
		pid_t pid = getpid();
		XChangeProperty(m_display, m_window, _NET_WM_PID, XA_CARDINAL,
		                32, PropModeReplace, (unsigned char *)&pid, 1);
	}


	/* set the hostname (WM_CLIENT_MACHINE) */
	{
		char  hostname[HOST_NAME_MAX];
		char *text_array[1];
		XTextProperty text_prop;

		gethostname(hostname, sizeof(hostname));
		hostname[sizeof(hostname) - 1] = '\0';
		text_array[0] = hostname;

		XStringListToTextProperty(text_array, 1, &text_prop);
		XSetWMClientMachine(m_display, m_window, &text_prop);
		XFree(text_prop.value);
	}

#ifdef WITH_X11_XINPUT
	refreshXInputDevices();

	m_tabletData.Active = GHOST_kTabletModeNone;
#endif


	/* now set up the rendering context. */
	if (setDrawingContextType(type) == GHOST_kSuccess) {
		m_valid_setup = true;
		GHOST_PRINT("Created window\n");
	}

	setTitle(title);

	if (exclusive && system->m_windowFocus) {
		XMapRaised(m_display, m_window);
	}
	else {
		XMapWindow(m_display, m_window);

		if (!system->m_windowFocus) {
			XLowerWindow(m_display, m_window);
		}
	}
	GHOST_PRINT("Mapped window\n");

	XFlush(m_display);
}

#if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
static Bool destroyICCallback(XIC /*xic*/, XPointer ptr, XPointer /*data*/)
{
	GHOST_PRINT("XIM input context destroyed\n");

	if (ptr) {
		*(XIC *)ptr = NULL;
	}
	/* Ignored by X11. */
	return True;
}

bool GHOST_WindowX11::createX11_XIC()
{
	XIM xim = m_system->getX11_XIM();
	if (!xim)
		return false;

	XICCallback destroy;
	destroy.callback = (XICProc)destroyICCallback;
	destroy.client_data = (XPointer)&m_xic;
	m_xic = XCreateIC(xim, XNClientWindow, m_window, XNFocusWindow, m_window,
	                  XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
	                  XNResourceName, GHOST_X11_RES_NAME,
	                  XNResourceClass, GHOST_X11_RES_CLASS,
	                  XNDestroyCallback, &destroy,
	                  NULL);
	if (!m_xic)
		return false;

	unsigned long fevent;
	XGetICValues(m_xic, XNFilterEvents, &fevent, NULL);
	XSelectInput(m_display, m_window,
	             ExposureMask | StructureNotifyMask |
	             KeyPressMask | KeyReleaseMask |
	             EnterWindowMask | LeaveWindowMask |
	             ButtonPressMask | ButtonReleaseMask |
	             PointerMotionMask | FocusChangeMask |
	             PropertyChangeMask | KeymapStateMask | fevent);
	return true;
}
#endif

#ifdef WITH_X11_XINPUT
void GHOST_WindowX11::refreshXInputDevices()
{
	if (m_system->m_xinput_version.present) {
		std::vector<XEventClass> xevents;

		for (GHOST_SystemX11::GHOST_TabletX11& xtablet: m_system->GetXTablets()) {
			/* With modern XInput (xlib 1.6.2 at least and/or evdev 2.9.0) and some 'no-name' tablets
			 * like 'UC-LOGIC Tablet WP5540U', we also need to 'select' ButtonPress for motion event,
			 * otherwise we do not get any tablet motion event once pen is pressed... See T43367.
			 */
			XEventClass ev;

			DeviceMotionNotify(xtablet.Device, xtablet.MotionEvent, ev);
			if (ev) xevents.push_back(ev);
			DeviceButtonPress(xtablet.Device, xtablet.PressEvent, ev);
			if (ev) xevents.push_back(ev);
			ProximityIn(xtablet.Device, xtablet.ProxInEvent, ev);
			if (ev) xevents.push_back(ev);
			ProximityOut(xtablet.Device, xtablet.ProxOutEvent, ev);
			if (ev) xevents.push_back(ev);
		}

		XSelectExtensionEvent(m_display, m_window, xevents.data(), (int)xevents.size());
	}
}

#endif /* WITH_X11_XINPUT */

Window
GHOST_WindowX11::
getXWindow()
{
	return m_window;
}

bool
GHOST_WindowX11::
getValid() const
{
	return GHOST_Window::getValid() && m_valid_setup;
}

void
GHOST_WindowX11::
setTitle(
		const STR_String& title)
{
	Atom name = XInternAtom(m_display, "_NET_WM_NAME", 0);
	Atom utf8str = XInternAtom(m_display, "UTF8_STRING", 0);
	XChangeProperty(m_display, m_window,
	                name, utf8str, 8, PropModeReplace,
	                (const unsigned char *) title.ReadPtr(),
	                title.Length());

	/* This should convert to valid x11 string
	 * and getTitle would need matching change */
	XStoreName(m_display, m_window, title);

	XFlush(m_display);
}

void
GHOST_WindowX11::
getTitle(
		STR_String& title) const
{
	char *name = NULL;

	XFetchName(m_display, m_window, &name);
	title = name ? name : "untitled";
	XFree(name);
}

void
GHOST_WindowX11::
getWindowBounds(
		GHOST_Rect& bounds) const
{
	/* Getting the window bounds under X11 is not
	 * really supported (nor should it be desired). */
	getClientBounds(bounds);
}

void
GHOST_WindowX11::
getClientBounds(
		GHOST_Rect& bounds) const
{
	Window root_return;
	int x_return, y_return;
	unsigned int w_return, h_return, border_w_return, depth_return;
	GHOST_TInt32 screen_x, screen_y;

	XGetGeometry(m_display, m_window, &root_return, &x_return, &y_return,
	             &w_return, &h_return, &border_w_return, &depth_return);

	clientToScreen(0, 0, screen_x, screen_y);

	bounds.m_l = screen_x;
	bounds.m_r = bounds.m_l + w_return;
	bounds.m_t = screen_y;
	bounds.m_b = bounds.m_t + h_return;

}

GHOST_TSuccess
GHOST_WindowX11::
setClientWidth(
		GHOST_TUns32 width)
{
	XWindowChanges values;
	unsigned int value_mask = CWWidth;
	values.width = width;
	XConfigureWindow(m_display, m_window, value_mask, &values);

	return GHOST_kSuccess;
}

GHOST_TSuccess
GHOST_WindowX11::
setClientHeight(
		GHOST_TUns32 height)
{
	XWindowChanges values;
	unsigned int value_mask = CWHeight;
	values.height = height;
	XConfigureWindow(m_display, m_window, value_mask, &values);
	return GHOST_kSuccess;

}

GHOST_TSuccess
GHOST_WindowX11::
setClientSize(
		GHOST_TUns32 width,
		GHOST_TUns32 height)
{
	XWindowChanges values;
	unsigned int value_mask = CWWidth | CWHeight;
	values.width = width;
	values.height = height;
	XConfigureWindow(m_display, m_window, value_mask, &values);
	return GHOST_kSuccess;

}

void
GHOST_WindowX11::
screenToClient(
		GHOST_TInt32 inX,
		GHOST_TInt32 inY,
		GHOST_TInt32& outX,
		GHOST_TInt32& outY) const
{
	/* This is correct! */

	int ax, ay;
	Window temp;

	XTranslateCoordinates(m_display,
	                      RootWindow(m_display, m_visualInfo->screen),
	                      m_window,
	                      inX, inY,
	                      &ax, &ay,
	                      &temp);
	outX = ax;
	outY = ay;
}

void
GHOST_WindowX11::
clientToScreen(
		GHOST_TInt32 inX,
		GHOST_TInt32 inY,
		GHOST_TInt32& outX,
		GHOST_TInt32& outY) const
{
	int ax, ay;
	Window temp;

	XTranslateCoordinates(
	    m_display,
	    m_window,
	    RootWindow(m_display, m_visualInfo->screen),
	    inX, inY,
	    &ax, &ay,
	    &temp);
	outX = ax;
	outY = ay;
}

void GHOST_WindowX11::icccmSetState(int state)
{
	XEvent xev;

	if (state != IconicState)
		return;

	xev.xclient.type = ClientMessage;
	xev.xclient.serial = 0;
	xev.xclient.send_event = True;
	xev.xclient.display = m_display;
	xev.xclient.window = m_window;
	xev.xclient.format = 32;
	xev.xclient.message_type = m_system->m_atom.WM_CHANGE_STATE;
	xev.xclient.data.l[0] = state;
	XSendEvent(m_display, RootWindow(m_display, m_visualInfo->screen),
	           False, SubstructureNotifyMask | SubstructureRedirectMask, &xev);
}

int GHOST_WindowX11::icccmGetState(void) const
{
	struct {
		CARD32 state;
		XID    icon;
	} *prop_ret;
	unsigned long bytes_after, num_ret;
	Atom type_ret;
	int ret, format_ret;
	CARD32 st;

	prop_ret = NULL;
	ret = XGetWindowProperty(
	        m_display, m_window, m_system->m_atom.WM_STATE, 0, 2,
	        False, m_system->m_atom.WM_STATE, &type_ret,
	        &format_ret, &num_ret, &bytes_after, ((unsigned char **)&prop_ret));
	if ((ret == Success) && (prop_ret != NULL) && (num_ret == 2)) {
		st = prop_ret->state;
	}
	else {
		st = NormalState;
	}

	if (prop_ret) {
		XFree(prop_ret);
	}

	return st;
}

void GHOST_WindowX11::netwmMaximized(bool set)
{
	XEvent xev;

	xev.xclient.type = ClientMessage;
	xev.xclient.serial = 0;
	xev.xclient.send_event = True;
	xev.xclient.window = m_window;
	xev.xclient.message_type = m_system->m_atom._NET_WM_STATE;
	xev.xclient.format = 32;

	if (set == True)
		xev.xclient.data.l[0] = _NET_WM_STATE_ADD;
	else
		xev.xclient.data.l[0] = _NET_WM_STATE_REMOVE;

	xev.xclient.data.l[1] = m_system->m_atom._NET_WM_STATE_MAXIMIZED_HORZ;
	xev.xclient.data.l[2] = m_system->m_atom._NET_WM_STATE_MAXIMIZED_VERT;
	xev.xclient.data.l[3] = 0;
	xev.xclient.data.l[4] = 0;
	XSendEvent(m_display, RootWindow(m_display, m_visualInfo->screen),
	           False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
}

bool GHOST_WindowX11::netwmIsMaximized(void) const
{
	Atom *prop_ret;
	unsigned long bytes_after, num_ret, i;
	Atom type_ret;
	bool st;
	int format_ret, ret, count;

	prop_ret = NULL;
	st = False;
	ret = XGetWindowProperty(
	        m_display, m_window, m_system->m_atom._NET_WM_STATE, 0, INT_MAX,
	        False, XA_ATOM, &type_ret, &format_ret,
	        &num_ret, &bytes_after, (unsigned char **)&prop_ret);
	if ((ret == Success) && (prop_ret) && (format_ret == 32)) {
		count = 0;
		for (i = 0; i < num_ret; i++) {
			if (prop_ret[i] == m_system->m_atom._NET_WM_STATE_MAXIMIZED_HORZ) {
				count++;
			}
			if (prop_ret[i] == m_system->m_atom._NET_WM_STATE_MAXIMIZED_VERT) {
				count++;
			}
			if (count == 2) {
				st = True;
				break;
			}
		}
	}

	if (prop_ret)
		XFree(prop_ret);
	return (st);
}

void GHOST_WindowX11::netwmFullScreen(bool set)
{
	XEvent xev;

	xev.xclient.type = ClientMessage;
	xev.xclient.serial = 0;
	xev.xclient.send_event = True;
	xev.xclient.window = m_window;
	xev.xclient.message_type = m_system->m_atom._NET_WM_STATE;
	xev.xclient.format = 32;

	if (set == True)
		xev.xclient.data.l[0] = _NET_WM_STATE_ADD;
	else
		xev.xclient.data.l[0] = _NET_WM_STATE_REMOVE;

	xev.xclient.data.l[1] = m_system->m_atom._NET_WM_STATE_FULLSCREEN;
	xev.xclient.data.l[2] = 0;
	xev.xclient.data.l[3] = 0;
	xev.xclient.data.l[4] = 0;
	XSendEvent(m_display, RootWindow(m_display, m_visualInfo->screen),
	           False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
}

bool GHOST_WindowX11::netwmIsFullScreen(void) const
{
	Atom *prop_ret;
	unsigned long bytes_after, num_ret, i;
	Atom type_ret;
	bool st;
	int format_ret, ret;

	prop_ret = NULL;
	st = False;
	ret = XGetWindowProperty(
	        m_display, m_window, m_system->m_atom._NET_WM_STATE, 0, INT_MAX,
	        False, XA_ATOM, &type_ret, &format_ret,
	        &num_ret, &bytes_after, (unsigned char **)&prop_ret);
	if ((ret == Success) && (prop_ret) && (format_ret == 32)) {
		for (i = 0; i < num_ret; i++) {
			if (prop_ret[i] == m_system->m_atom._NET_WM_STATE_FULLSCREEN) {
				st = True;
				break;
			}
		}
	}

	if (prop_ret)
		XFree(prop_ret);
	return (st);
}

void GHOST_WindowX11::motifFullScreen(bool set)
{
	MotifWmHints hints;

	hints.flags = MWM_HINTS_DECORATIONS;
	if (set == True)
		hints.decorations = 0;
	else
		hints.decorations = 1;

	XChangeProperty(m_display, m_window, m_system->m_atom._MOTIF_WM_HINTS,
	                m_system->m_atom._MOTIF_WM_HINTS, 32, PropModeReplace,
	                (unsigned char *) &hints, 4);
}

bool GHOST_WindowX11::motifIsFullScreen(void) const
{
	MotifWmHints *prop_ret;
	unsigned long bytes_after, num_ret;
	Atom type_ret;
	bool state;
	int format_ret, st;

	prop_ret = NULL;
	state = False;
	st = XGetWindowProperty(
	        m_display, m_window, m_system->m_atom._MOTIF_WM_HINTS, 0, INT_MAX,
	        False, m_system->m_atom._MOTIF_WM_HINTS,
	        &type_ret, &format_ret, &num_ret,
	        &bytes_after, (unsigned char **)&prop_ret);
	if ((st == Success) && prop_ret) {
		if (prop_ret->flags & MWM_HINTS_DECORATIONS) {
			if (!prop_ret->decorations)
				state = True;
		}
	}

	if (prop_ret)
		XFree(prop_ret);
	return (state);
}

GHOST_TWindowState GHOST_WindowX11::getState() const
{
	GHOST_TWindowState state_ret;
	int state;

	state_ret = GHOST_kWindowStateNormal;
	state = icccmGetState();
	/*
	 * In the Iconic and Withdrawn state, the window
	 * is unmaped, so only need return a Minimized state.
	 */
	if ((state == IconicState) || (state == WithdrawnState))
		state_ret = GHOST_kWindowStateMinimized;
	else if (netwmIsFullScreen() == True)
		state_ret = GHOST_kWindowStateFullScreen;
	else if (motifIsFullScreen() == True)
		state_ret = GHOST_kWindowStateFullScreen;
	else if (netwmIsMaximized() == True)
		state_ret = GHOST_kWindowStateMaximized;
	return (state_ret);
}

GHOST_TSuccess GHOST_WindowX11::setState(GHOST_TWindowState state)
{
	GHOST_TWindowState cur_state;
	bool is_max, is_full, is_motif_full;

	cur_state = getState();
	if (state == (int)cur_state)
		return GHOST_kSuccess;

	if (cur_state != GHOST_kWindowStateMinimized) {
		/*
		 * The window don't have this property's
		 * if it's not mapped.
		 */
		is_max = netwmIsMaximized();
		is_full = netwmIsFullScreen();
	}
	else {
		is_max = False;
		is_full = False;
	}

	is_motif_full = motifIsFullScreen();

	if (state == GHOST_kWindowStateNormal)
		state = m_normal_state;

	if (state == GHOST_kWindowStateNormal) {
		if (is_max == True)
			netwmMaximized(False);
		if (is_full == True)
			netwmFullScreen(False);
		if (is_motif_full == True)
			motifFullScreen(False);
		icccmSetState(NormalState);
		return (GHOST_kSuccess);
	}

	if (state == GHOST_kWindowStateFullScreen) {
		/*
		 * We can't change to full screen if the window
		 * isn't mapped.
		 */
		if (cur_state == GHOST_kWindowStateMinimized)
			return (GHOST_kFailure);

		m_normal_state = cur_state;

		if (is_max == True)
			netwmMaximized(False);
		if (is_full == False)
			netwmFullScreen(True);
		if (is_motif_full == False)
			motifFullScreen(True);
		return (GHOST_kSuccess);
	}

	if (state == GHOST_kWindowStateMaximized) {
		/*
		 * We can't change to Maximized if the window
		 * isn't mapped.
		 */
		if (cur_state == GHOST_kWindowStateMinimized)
			return (GHOST_kFailure);

		if (is_full == True)
			netwmFullScreen(False);
		if (is_motif_full == True)
			motifFullScreen(False);
		if (is_max == False)
			netwmMaximized(True);
		return (GHOST_kSuccess);
	}

	if (state == GHOST_kWindowStateMinimized) {
		/*
		 * The window manager need save the current state of
		 * the window (maximized, full screen, etc).
		 */
		icccmSetState(IconicState);
		return (GHOST_kSuccess);
	}

	return (GHOST_kFailure);
}

#include <iostream>

GHOST_TSuccess
GHOST_WindowX11::
setOrder(
		GHOST_TWindowOrder order)
{
	if (order == GHOST_kWindowOrderTop) {
		XWindowAttributes attr;
		Atom atom;

		/* We use both XRaiseWindow and _NET_ACTIVE_WINDOW, since some
		 * window managers ignore the former (e.g. kwin from kde) and others
		 * don't implement the latter (e.g. fluxbox pre 0.9.9) */

		XRaiseWindow(m_display, m_window);

		atom = XInternAtom(m_display, "_NET_ACTIVE_WINDOW", True);

		if (atom != None) {
			Window root;
			XEvent xev;
			long eventmask;

			xev.xclient.type = ClientMessage;
			xev.xclient.serial = 0;
			xev.xclient.send_event = True;
			xev.xclient.window = m_window;
			xev.xclient.message_type = atom;

			xev.xclient.format = 32;
			xev.xclient.data.l[0] = 1;
			xev.xclient.data.l[1] = CurrentTime;
			xev.xclient.data.l[2] = m_window;
			xev.xclient.data.l[3] = 0;
			xev.xclient.data.l[4] = 0;

			root = RootWindow(m_display, m_visualInfo->screen);
			eventmask = SubstructureRedirectMask | SubstructureNotifyMask;

			XSendEvent(m_display, root, False, eventmask, &xev);
		}

		XGetWindowAttributes(m_display, m_window, &attr);

		/* iconized windows give bad match error */
		if (attr.map_state == IsViewable)
			XSetInputFocus(m_display, m_window, RevertToPointerRoot,
			               CurrentTime);
		XFlush(m_display);
	}
	else if (order == GHOST_kWindowOrderBottom) {
		XLowerWindow(m_display, m_window);
		XFlush(m_display);
	}
	else {
		return GHOST_kFailure;
	}

	return GHOST_kSuccess;
}

GHOST_TSuccess
GHOST_WindowX11::
invalidate()
{
	/* So the idea of this function is to generate an expose event
	 * for the window.
	 * Unfortunately X does not handle expose events for you and
	 * it is the client's job to refresh the dirty part of the window.
	 * We need to queue up invalidate calls and generate GHOST events
	 * for them in the system.
	 *
	 * We implement this by setting a boolean in this class to concatenate
	 * all such calls into a single event for this window.
	 *
	 * At the same time we queue the dirty windows in the system class
	 * and generate events for them at the next processEvents call. */

	if (m_invalid_window == false) {
		m_system->addDirtyWindow(this);
		m_invalid_window = true;
	}

	return GHOST_kSuccess;
}

/**
 * called by the X11 system implementation when expose events
 * for the window have been pushed onto the GHOST queue
 */

void
GHOST_WindowX11::
validate()
{
	m_invalid_window = false;
}


/**
 * Destructor.
 * Closes the window and disposes resources allocated.
 */

GHOST_WindowX11::
~GHOST_WindowX11()
{
	std::map<unsigned int, Cursor>::iterator it = m_standard_cursors.begin();
	for (; it != m_standard_cursors.end(); ++it) {
		XFreeCursor(m_display, it->second);
	}

	if (m_empty_cursor) {
		XFreeCursor(m_display, m_empty_cursor);
	}
	if (m_custom_cursor) {
		XFreeCursor(m_display, m_custom_cursor);
	}

	if (m_valid_setup) {
		static Atom Primary_atom, Clipboard_atom;
		Window p_owner, c_owner;
		/*Change the owner of the Atoms to None if we are the owner*/
		Primary_atom = XInternAtom(m_display, "PRIMARY", False);
		Clipboard_atom = XInternAtom(m_display, "CLIPBOARD", False);


		p_owner = XGetSelectionOwner(m_display, Primary_atom);
		c_owner = XGetSelectionOwner(m_display, Clipboard_atom);

		if (p_owner == m_window) {
			XSetSelectionOwner(m_display, Primary_atom, None, CurrentTime);
		}
		if (c_owner == m_window) {
			XSetSelectionOwner(m_display, Clipboard_atom, None, CurrentTime);
		}
	}

	if (m_visualInfo) {
		XFree(m_visualInfo);
	}

#if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
	if (m_xic) {
		XDestroyIC(m_xic);
	}
#endif

#ifdef WITH_XDND
	delete m_dropTarget;
#endif

	releaseNativeHandles();

	if (m_valid_setup) {
		XDestroyWindow(m_display, m_window);
	}
}


GHOST_Context *GHOST_WindowX11::newDrawingContext(GHOST_TDrawingContextType type)
{
	if (type == GHOST_kDrawingContextTypeOpenGL) {

		// During development:
		//   try 4.x compatibility profile
		//   try 3.3 compatibility profile
		//   fall back to 3.0 if needed
		//
		// Final Blender 2.8:
		//   try 4.x core profile
		//   try 3.3 core profile
		//   no fallbacks

#if defined(WITH_GL_PROFILE_CORE)
		{
			const char *version_major = (char*)glewGetString(GLEW_VERSION_MAJOR);
			if (version_major != NULL && version_major[0] == '1') {
				fprintf(stderr, "Error: GLEW version 2.0 and above is required.\n");
				abort();
			}
		}
#endif

		const int profile_mask =
#if defined(WITH_GL_PROFILE_CORE)
			GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
#elif defined(WITH_GL_PROFILE_COMPAT)
			GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
#else
#  error // must specify either core or compat at build time
#endif

		GHOST_Context *context;

		for (int minor = 5; minor >= 0; --minor) {
			context = new GHOST_ContextGLX(
			        m_wantStereoVisual,
			        m_wantNumOfAASamples,
			        m_window,
			        m_display,
			        (GLXFBConfig)m_fbconfig,
			        profile_mask,
			        4, minor,
			        GHOST_OPENGL_GLX_CONTEXT_FLAGS | (m_is_debug_context ? GLX_CONTEXT_DEBUG_BIT_ARB : 0),
			        GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY);

			if (context->initializeDrawingContext())
				return context;
			else
				delete context;
		}

		context = new GHOST_ContextGLX(
		        m_wantStereoVisual,
		        m_wantNumOfAASamples,
		        m_window,
		        m_display,
		        (GLXFBConfig)m_fbconfig,
		        profile_mask,
		        3, 3,
		        GHOST_OPENGL_GLX_CONTEXT_FLAGS | (m_is_debug_context ? GLX_CONTEXT_DEBUG_BIT_ARB : 0),
		        GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY);

		if (context->initializeDrawingContext())
			return context;
		else
			delete context;

	}

	return NULL;
}


Cursor
GHOST_WindowX11::
getStandardCursor(
		GHOST_TStandardCursor g_cursor)
{
	unsigned int xcursor_id;

#define GtoX(gcurs, xcurs)  case gcurs: xcursor_id = xcurs
	switch (g_cursor) {
		GtoX(GHOST_kStandardCursorRightArrow, XC_arrow); break;
		GtoX(GHOST_kStandardCursorLeftArrow, XC_top_left_arrow); break;
		GtoX(GHOST_kStandardCursorInfo, XC_hand1); break;
		GtoX(GHOST_kStandardCursorDestroy, XC_pirate); break;
		GtoX(GHOST_kStandardCursorHelp, XC_question_arrow); break;
		GtoX(GHOST_kStandardCursorCycle, XC_exchange); break;
		GtoX(GHOST_kStandardCursorSpray, XC_spraycan); break;
		GtoX(GHOST_kStandardCursorWait, XC_watch); break;
		GtoX(GHOST_kStandardCursorText, XC_xterm); break;
		GtoX(GHOST_kStandardCursorCrosshair, XC_crosshair); break;
		GtoX(GHOST_kStandardCursorUpDown, XC_sb_v_double_arrow); break;
		GtoX(GHOST_kStandardCursorLeftRight, XC_sb_h_double_arrow); break;
		GtoX(GHOST_kStandardCursorTopSide, XC_top_side); break;
		GtoX(GHOST_kStandardCursorBottomSide, XC_bottom_side); break;
		GtoX(GHOST_kStandardCursorLeftSide, XC_left_side); break;
		GtoX(GHOST_kStandardCursorRightSide, XC_right_side); break;
		GtoX(GHOST_kStandardCursorTopLeftCorner, XC_top_left_corner); break;
		GtoX(GHOST_kStandardCursorTopRightCorner, XC_top_right_corner); break;
		GtoX(GHOST_kStandardCursorBottomRightCorner, XC_bottom_right_corner); break;
		GtoX(GHOST_kStandardCursorBottomLeftCorner, XC_bottom_left_corner); break;
		GtoX(GHOST_kStandardCursorPencil, XC_pencil); break;
		GtoX(GHOST_kStandardCursorCopy, XC_arrow); break;
		default:
			xcursor_id = 0;
	}
#undef GtoX

	if (xcursor_id) {
		Cursor xcursor = m_standard_cursors[xcursor_id];

		if (!xcursor) {
			xcursor = XCreateFontCursor(m_display, xcursor_id);

			m_standard_cursors[xcursor_id] = xcursor;
		}

		return xcursor;
	}
	else {
		return None;
	}
}

Cursor
GHOST_WindowX11::
getEmptyCursor(
        ) {
	if (!m_empty_cursor) {
		Pixmap blank;
		XColor dummy = {0};
		char data[1] = {0};

		/* make a blank cursor */
		blank = XCreateBitmapFromData(
		    m_display,
		    RootWindow(m_display, m_visualInfo->screen),
		    data, 1, 1
		    );

		m_empty_cursor = XCreatePixmapCursor(m_display, blank, blank, &dummy, &dummy, 0, 0);
		XFreePixmap(m_display, blank);
	}

	return m_empty_cursor;
}

GHOST_TSuccess
GHOST_WindowX11::
setWindowCursorVisibility(
		bool visible)
{
	Cursor xcursor;

	if (visible) {
		if (m_visible_cursor)
			xcursor = m_visible_cursor;
		else
			xcursor = getStandardCursor(getCursorShape() );
	}
	else {
		xcursor = getEmptyCursor();
	}

	XDefineCursor(m_display, m_window, xcursor);
	XFlush(m_display);

	return GHOST_kSuccess;
}

GHOST_TSuccess
GHOST_WindowX11::
setWindowCursorGrab(
		GHOST_TGrabCursorMode mode)
{
	if (mode != GHOST_kGrabDisable) {
		if (mode != GHOST_kGrabNormal) {
			m_system->getCursorPosition(m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]);
			setCursorGrabAccum(0, 0);

			if (mode == GHOST_kGrabHide)
				setWindowCursorVisibility(false);

		}
#ifdef GHOST_X11_GRAB
		XGrabPointer(m_display, m_window, False, ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
		             GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
#endif
	}
	else {
		if (m_cursorGrab == GHOST_kGrabHide) {
			m_system->setCursorPosition(m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]);
		}

		if (m_cursorGrab != GHOST_kGrabNormal) {
			/* use to generate a mouse move event, otherwise the last event
			 * blender gets can be outside the screen causing menus not to show
			 * properly unless the user moves the mouse */

#ifdef WITH_X11_XINPUT
			if ((m_system->m_xinput_version.present) &&
			    (m_system->m_xinput_version.major_version >= 2))
			{
				int device_id;
				if (XIGetClientPointer(m_display, None, &device_id) != False) {
					XIWarpPointer(m_display, device_id, None, None, 0, 0, 0, 0, 0, 0);
				}
			}
			else
#endif
			{
				XWarpPointer(m_display, None, None, 0, 0, 0, 0, 0, 0);
			}
		}

		/* Perform this last so to workaround XWayland bug, see: T53004. */
		if (m_cursorGrab == GHOST_kGrabHide) {
			setWindowCursorVisibility(true);
		}

		/* Almost works without but important otherwise the mouse GHOST location can be incorrect on exit */
		setCursorGrabAccum(0, 0);
		m_cursorGrabBounds.m_l = m_cursorGrabBounds.m_r = -1; /* disable */
#ifdef GHOST_X11_GRAB
		XUngrabPointer(m_display, CurrentTime);
#endif
	}

	XFlush(m_display);

	return GHOST_kSuccess;
}

GHOST_TSuccess
GHOST_WindowX11::
setWindowCursorShape(
		GHOST_TStandardCursor shape)
{
	Cursor xcursor = getStandardCursor(shape);

	m_visible_cursor = xcursor;

	XDefineCursor(m_display, m_window, xcursor);
	XFlush(m_display);

	return GHOST_kSuccess;
}

GHOST_TSuccess
GHOST_WindowX11::
setWindowCustomCursorShape(
		GHOST_TUns8 bitmap[16][2],
		GHOST_TUns8 mask[16][2],
		int hotX,
		int hotY)
{
	setWindowCustomCursorShape((GHOST_TUns8 *)bitmap, (GHOST_TUns8 *)mask,
	                           16, 16, hotX, hotY, 0, 1);
	return GHOST_kSuccess;
}

GHOST_TSuccess
GHOST_WindowX11::
setWindowCustomCursorShape(
		GHOST_TUns8 *bitmap,
		GHOST_TUns8 *mask,
		int sizex,
		int sizey,
		int hotX,
		int hotY,
		int /*fg_color*/,
		int /*bg_color*/)
{
	Colormap colormap = DefaultColormap(m_display, m_visualInfo->screen);
	Pixmap bitmap_pix, mask_pix;
	XColor fg, bg;

	if (XAllocNamedColor(m_display, colormap, "White", &fg, &fg) == 0) return GHOST_kFailure;
	if (XAllocNamedColor(m_display, colormap, "Black", &bg, &bg) == 0) return GHOST_kFailure;

	if (m_custom_cursor) {
		XFreeCursor(m_display, m_custom_cursor);
	}

	bitmap_pix = XCreateBitmapFromData(m_display, m_window, (char *) bitmap, sizex, sizey);
	mask_pix = XCreateBitmapFromData(m_display, m_window, (char *) mask, sizex, sizey);

	m_custom_cursor = XCreatePixmapCursor(m_display, bitmap_pix, mask_pix, &fg, &bg, hotX, hotY);
	XDefineCursor(m_display, m_window, m_custom_cursor);
	XFlush(m_display);

	m_visible_cursor = m_custom_cursor;

	XFreePixmap(m_display, bitmap_pix);
	XFreePixmap(m_display, mask_pix);

	XFreeColors(m_display, colormap, &fg.pixel, 1, 0L);
	XFreeColors(m_display, colormap, &bg.pixel, 1, 0L);

	return GHOST_kSuccess;
}


GHOST_TSuccess
GHOST_WindowX11::
beginFullScreen() const
{
	{
		Window root_return;
		int x_return, y_return;
		unsigned int w_return, h_return, border_w_return, depth_return;

		XGetGeometry(m_display, m_window, &root_return, &x_return, &y_return,
		             &w_return, &h_return, &border_w_return, &depth_return);

		m_system->setCursorPosition(w_return / 2, h_return / 2);
	}


	/* Grab Keyboard & Mouse */
	int err;

	err = XGrabKeyboard(m_display, m_window, False,
	                    GrabModeAsync, GrabModeAsync, CurrentTime);
	if (err != GrabSuccess) printf("XGrabKeyboard failed %d\n", err);

	err = XGrabPointer(m_display, m_window, False,  PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
	                   GrabModeAsync, GrabModeAsync, m_window, None, CurrentTime);
	if (err != GrabSuccess) printf("XGrabPointer failed %d\n", err);

	return GHOST_kSuccess;
}

GHOST_TSuccess
GHOST_WindowX11::
endFullScreen() const
{
	XUngrabKeyboard(m_display, CurrentTime);
	XUngrabPointer(m_display, CurrentTime);

	return GHOST_kSuccess;
}

GHOST_TUns16
GHOST_WindowX11::
getDPIHint()
{
	/* Try to read DPI setting set using xrdb */
	char* resMan = XResourceManagerString(m_display);
	if (resMan) {
		XrmDatabase xrdb = XrmGetStringDatabase(resMan);
		if (xrdb) {
			char* type = NULL;
			XrmValue val;

			int success = XrmGetResource(xrdb, "Xft.dpi", "Xft.Dpi", &type, &val);
			if (success && type) {
				if (strcmp(type, "String") == 0) {
					return atoi((char*)val.addr);
				}
			}
		}
		XrmDestroyDatabase(xrdb);
	}

	/* Fallback to calculating DPI using X reported DPI, set using xrandr --dpi */
	XWindowAttributes attr;
	if (!XGetWindowAttributes(m_display, m_window, &attr)) {
		/* Failed to get window attributes, return X11 default DPI */
		return 96;
	}

	Screen* screen = attr.screen;
	int pixelWidth = WidthOfScreen(screen);
	int pixelHeight = HeightOfScreen(screen);
	int mmWidth = WidthMMOfScreen(screen);
	int mmHeight = HeightMMOfScreen(screen);

	double pixelDiagonal = sqrt((pixelWidth * pixelWidth) + (pixelHeight * pixelHeight));
	double mmDiagonal = sqrt((mmWidth * mmWidth) + (mmHeight * mmHeight));
	float inchDiagonal = mmDiagonal * 0.039f;
	int dpi = pixelDiagonal / inchDiagonal;
	return dpi;
}

GHOST_TSuccess GHOST_WindowX11::setProgressBar(float progress)
{
	if (m_taskbar.is_valid()) {
		m_taskbar.set_progress(progress);
		m_taskbar.set_progress_enabled(true);
		return GHOST_kSuccess;
	}

	return GHOST_kFailure;
}

GHOST_TSuccess GHOST_WindowX11::endProgressBar()
{
	if (m_taskbar.is_valid()) {
		m_taskbar.set_progress_enabled(false);
		return GHOST_kSuccess;
	}

	return GHOST_kFailure;
}
